Package com.serotonin.m2m2.envcan

Source Code of com.serotonin.m2m2.envcan.EnvCanDataSourceRT

/*
    Copyright (C) 2014 Infinite Automation Systems Inc. All rights reserved.
    @author Matthew Lohbihler
*/
package com.serotonin.m2m2.envcan;

import java.util.TimeZone;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import com.serotonin.m2m2.Common;
import com.serotonin.m2m2.i18n.TranslatableException;
import com.serotonin.m2m2.i18n.TranslatableMessage;
import com.serotonin.m2m2.rt.dataImage.DataPointRT;
import com.serotonin.m2m2.rt.dataImage.PointValueTime;
import com.serotonin.m2m2.rt.dataImage.SetPointSource;
import com.serotonin.m2m2.rt.dataSource.DataSourceRT;
import com.serotonin.m2m2.rt.dataSource.PollingDataSource;
import com.serotonin.util.XmlUtilsTS;
import com.serotonin.web.http.HttpUtils4;

/**
* @author Matthew Lohbihler
*/
public class EnvCanDataSourceRT extends PollingDataSource {
    public static final int DATA_RETRIEVAL_FAILURE_EVENT = 1;
    public static final int PARSE_EXCEPTION_EVENT = 2;

    private final EnvCanDataSourceVO vo;
    private long nextValueTime = -1;
    private long tzOffset;

    public EnvCanDataSourceRT(EnvCanDataSourceVO vo) {
        super(vo);
        this.vo = vo;
        setPollingPeriod(Common.TimePeriods.HOURS, 1, false);
    }

    @Override
    public void removeDataPoint(DataPointRT dataPoint) {
        returnToNormal(PARSE_EXCEPTION_EVENT, System.currentTimeMillis());
        super.removeDataPoint(dataPoint);
    }

    @Override
    public void setPointValue(DataPointRT dataPoint, PointValueTime valueTime, SetPointSource source) {
        // no op
    }

    @Override
    public void initialize() {
        tzOffset = TimeZone.getDefault().getRawOffset();
    }

    @Override
    protected void doPoll(long time) {
        if (nextValueTime == -1) {
            // Determine when we should start from
            nextValueTime = System.currentTimeMillis();
            for (DataPointRT dp : dataPoints) {
                PointValueTime pvt = dp.getPointValue();
                if (pvt == null) {
                    nextValueTime = 0;
                    break;
                }
                if (nextValueTime > pvt.getTime())
                    nextValueTime = pvt.getTime();
            }

            if (nextValueTime == 0)
                nextValueTime = new DateTime(2008, 1, 1, 0, 0, 0, 0).getMillis();
            else
                nextValueTime += 1000 * 60 * 60;
        }

        long previousValueTime = nextValueTime;
        doPollImpl(time);

        while (nextValueTime != previousValueTime) {
            // Something was changed.
            DateTime prev = new DateTime(previousValueTime);
            DateTime now = new DateTime(System.currentTimeMillis());
            if (prev.getYear() < now.getYear() || prev.getMonthOfYear() < now.getMonthOfYear()) {
                previousValueTime = nextValueTime;
                doPollImpl(time);
            }
            else
                break;
        }
    }

    private void doPollImpl(long runtime) {
        DateTime dt = new DateTime(nextValueTime);
        StringBuilder url = new StringBuilder();
        url.append("http://climate.weatheroffice.gc.ca/climateData/bulkdata_e.html?StationID=").append(
                vo.getStationId());
        url.append("&Year=").append(dt.getYear());
        url.append("&Month=").append(dt.getMonthOfYear() + 1);
        url.append("&format=xml&timeframe=1");

        String data;
        try {
            data = getData(url.toString(), 30, 2);
        }
        catch (Exception e) {
            TranslatableMessage lm;
            if (e instanceof TranslatableException)
                lm = ((TranslatableException) e).getTranslatableMessage();
            else
                lm = new TranslatableMessage("envcands.retrievalError", e.getMessage());
            raiseEvent(DATA_RETRIEVAL_FAILURE_EVENT, runtime, true, lm);
            return;
        }

        // If we made it this far, everything is good.
        returnToNormal(DATA_RETRIEVAL_FAILURE_EVENT, runtime);

        try {
            Document xml = XmlUtilsTS.parse(data);
            Element climateDataElement = xml.getDocumentElement();
            for (Element stationDataElement : XmlUtilsTS.getChildElements(climateDataElement, "stationdata")) {
                int year = XmlUtilsTS.getIntAttribute(stationDataElement, "year", -1);
                int month = XmlUtilsTS.getIntAttribute(stationDataElement, "month", -1);
                int day = XmlUtilsTS.getIntAttribute(stationDataElement, "day", -1);
                int hour = XmlUtilsTS.getIntAttribute(stationDataElement, "hour", -1);

                long time = new DateTime(year, month, day, hour, 0, 0, 0, DateTimeZone.UTC).getMillis();
                time -= tzOffset;

                double temp = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "temp", Double.NaN);
                double dptemp = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "dptemp", Double.NaN);
                double visibility = XmlUtilsTS
                        .getChildElementTextAsDouble(stationDataElement, "visibility", Double.NaN);
                double relhum = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "relhum", Double.NaN);
                double winddir = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "winddir", Double.NaN);
                double windspd = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "windspd", Double.NaN);
                double stnpress = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "stnpress", Double.NaN);
                double humidex = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "humidex", Double.NaN);
                double windchill = XmlUtilsTS.getChildElementTextAsDouble(stationDataElement, "windchill", Double.NaN);
                String weather = XmlUtilsTS.getChildElementText(stationDataElement, "weather");

                if (Double.isNaN(temp))
                    // If there is no temp value, ignore the record
                    continue;

                // Update the next value time.
                nextValueTime = time + 1000 * 60 * 60;

                for (DataPointRT dp : dataPoints) {
                    PointValueTime pvt = dp.getPointValue();
                    if (pvt != null && pvt.getTime() >= time)
                        // This value is in the past. Ignore it.
                        continue;

                    EnvCanPointLocatorVO plvo = dp.getVO().getPointLocator();
                    if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.TEMP && !Double.isNaN(temp))
                        pvt = new PointValueTime(temp, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.DEW_POINT_TEMP
                            && !Double.isNaN(dptemp))
                        pvt = new PointValueTime(dptemp, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.REL_HUM && !Double.isNaN(relhum))
                        pvt = new PointValueTime(relhum, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.WIND_DIR
                            && !Double.isNaN(winddir))
                        pvt = new PointValueTime(winddir, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.WIND_SPEED
                            && !Double.isNaN(windspd))
                        pvt = new PointValueTime(windspd, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.VISIBILITY
                            && !Double.isNaN(visibility))
                        pvt = new PointValueTime(visibility, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.STN_PRESS
                            && !Double.isNaN(stnpress))
                        pvt = new PointValueTime(stnpress, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.HUMIDEX && !Double.isNaN(humidex))
                        pvt = new PointValueTime(humidex, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.WIND_CHILL
                            && !Double.isNaN(windchill))
                        pvt = new PointValueTime(windchill, time);
                    else if (plvo.getAttributeId() == EnvCanPointLocatorVO.Attributes.WEATHER && weather != null)
                        pvt = new PointValueTime(weather, time);
                    else
                        continue;

                    dp.updatePointValue(pvt);
                }
            }

            returnToNormal(PARSE_EXCEPTION_EVENT, runtime);
        }
        catch (SAXException e) {
            raiseEvent(PARSE_EXCEPTION_EVENT, runtime, true, DataSourceRT.getExceptionMessage(e));
        }
    }

    private String getData(String url, int timeoutSeconds, int retries) throws TranslatableException {
        // Try to get the data.
        String data;
        while (true) {
            HttpClient client = Common.getHttpClient(timeoutSeconds * 1000);
            HttpGet request = null;
            TranslatableMessage message;

            try {
                request = new HttpGet(url);
                HttpResponse response = client.execute(request);
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    data = HttpUtils4.readResponseBody(response);
                    break;
                }
                message = new TranslatableMessage("event.http.response", url, response.getStatusLine().getStatusCode());
            }
            catch (Exception e) {
                message = DataSourceRT.getExceptionMessage(e);
            }
            finally {
                request.reset();
            }

            if (retries <= 0)
                throw new TranslatableException(message);
            retries--;

            // Take a little break instead of trying again immediately.
            try {
                Thread.sleep(10000);
            }
            catch (InterruptedException e) {
                // no op
            }
        }

        return data;
    }
}
TOP

Related Classes of com.serotonin.m2m2.envcan.EnvCanDataSourceRT

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.